package com.ydj.app.service;

import com.ydj.app.entity.Chat;
import com.ydj.app.entity.WebUser;
import com.ydj.app.entity.dao.ChatDao;
import com.ydj.app.entity.dao.WebUserDao;
import com.ydj.app.entity.query.ChatQuery;
import com.ydj.app.enumerate.ChatRoleEnum;
import com.ydj.app.protocol.http.stream.*;
import com.ydj.app.protocol.http.web.*;
import com.ydj.app.third.ai.AiModelService;
import com.ydj.app.third.ai.ChatFluxListener;
import com.ydj.framework.exception.CommonException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import springfox.documentation.annotations.ApiIgnore;

import javax.transaction.Transactional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * KOL相关服务
 */
@Slf4j
@Service
public class ChatService {
    @Autowired
    private AiModelService aiModelService;
    @Autowired
    private ChatDao chatDao;
    @Autowired
    private WebUserDao webUserDao;

    /**
     * 获取对话历史记录
     */
    public WebChatHistoryListRes webHistoryList(WebChatHistoryListReq req, WebUser webUser) {
        List<Chat> list = new ChatQuery(chatDao)
                .userId(webUser.getId())
                .orderByUpdateTimeDesc()
                .limit(10)
                .list();

        WebChatHistoryListRes res = new WebChatHistoryListRes();
        for (Chat chat : list) {
            WebChatHistoryListRes.WebChatHistoryListResItem item = new WebChatHistoryListRes.WebChatHistoryListResItem()
                    .setId(chat.getId())
                    .setFirstQuestion(chat.getFirstQuestion());
            res.getList().add(item);
        }
        return res;
    }

    /**
     * 清除对话历史记录
     */
    public void webClearHistory(WebChatClearHistoryReq req, WebUser webUser) {
        new ChatQuery(chatDao)
                .userId(webUser.getId())
                .remove();
    }

    /**
     * 获取一个对话的内容
     */
    public WebChatChatDetailRes webChatDetail(WebChatChatDetailReq req, WebUser webUser) throws CommonException {
        Chat chat = new ChatQuery(chatDao)
                .id(req.getId())
                .single();
        CommonException.throwExceptionIfNull(chat, "找不到对话");

        WebChatChatDetailRes res = new WebChatChatDetailRes()
                .setId(chat.getId())
                .setChatContentList(chat.getChatContentList());
        return res;
    }

    @Transactional(rollbackOn = Exception.class)
    public SseEmitter chat(Long reqChatId, String reqContent, @ApiIgnore WebUser webUser) throws CommonException {
        log.info("Chat new SseEmitter");
        // 建立流式SSE对象
        SseEmitter emitter = new SseEmitter(60 * 1000L);
        emitter.onCompletion(() -> System.out.println("全部发完了"));
        emitter.onTimeout(() -> {
            log.error("Chat SseEmitter 超时");
            emitter.complete();
        });
        emitter.onError((ex) -> {
            log.error("Chat SseEmitter 出错了：" + ex.getMessage());
            emitter.completeWithError(ex);
        });

        // 找不到webUser用户，也就是系统传入的token有问题
        if (webUser == null) {
            log.error("Chat 找不到webUser用户，也就是系统传入的token有问题");
            StreamVerifyTokenErrorItemRes resItem = new StreamVerifyTokenErrorItemRes();
            sendStreamMessage(emitter, resItem, true);
            return emitter;
        }

        // 如果不是会员了，或者会员过期了，检查免费次数
        log.info("Chat check isMemberInExpTime");
        if (!webUser.isMemberInExpTime()) {
            if (webUser.getFreeChatCount() <= 0) {
                log.info("Chat webUser.getFreeChatCount() <= 0");
                StreamOverFreeTimeItemRes resItem = new StreamOverFreeTimeItemRes();
                sendStreamMessage(emitter, resItem, true);
                return emitter;
            }
            webUser.incFreeChatCount(-1);
            webUserDao.saveOrUpdate(webUser);
        }
        Chat oriChat;
        if (reqChatId == null) {
            oriChat = new Chat()
                    .setUserId(webUser.getId())
                    .setNickname(webUser.getNickName())
                    .setFirstQuestion(reqContent)
                    .setChatContentList(new ArrayList<>());
            chatDao.saveOrUpdate(oriChat);
        } else {
            oriChat = chatDao.getById(reqChatId);
            CommonException.throwExceptionIfNull(oriChat, "该对话不存在, 请重开一个对话");
        }
        log.info("Chat new Chat Entity and save");

        Long chatId = oriChat.getId();

        // 用户输入的对话
        Chat.ChatContentItem userContentItem = new Chat.ChatContentItem()
                .setChatId(chatId)
                .setRole(ChatRoleEnum.用户.getProtocolName())
                .setContent(reqContent)
                .setTimestamp(System.currentTimeMillis());
        oriChat.addContentItem(userContentItem);
        chatDao.saveOrUpdate(oriChat);

        log.info("Chat start thread");
        new Thread(() -> {
            StringBuilder sbContent = new StringBuilder();
            Chat chat = oriChat;
            // 历史记录的
            List<Chat.ChatContentItem> chatHistory = chat.getChatContentList()
                    .stream()
                    .skip(Math.max(chat.getChatContentList().size() - 6, 0))
                    .collect(Collectors.toList());
            for (Iterator<Chat.ChatContentItem> ite = chatHistory.iterator(); ite.hasNext();) {
                Chat.ChatContentItem item = ite.next();
                if (ChatRoleEnum.用户.getProtocolName().equals(item.getRole())) {
                    break;
                } else {
                    ite.remove();;
                }
            }
            // 这里不带历史记录
//            List<Chat.ChatContentItem> chatHistory = new LinkedList<>();
//            chatHistory.add(userContentItem);

            StreamInfoItemRes infoItem = new StreamInfoItemRes()
                    .setMsg("开始调用chat请求");
            sendStreamMessage(emitter, infoItem, false);

            log.info("Chat aiModelService.chat()");
            aiModelService.chat(chatHistory, String.valueOf(webUser.getId()), new ChatFluxListener() {
                @Override
                public void flux(String content, boolean isFinish) {
                    if (isFinish) {
                        sendStreamMessage(emitter, null, true);
                        // 结束对话了，保存到数据库中，用来当聊天记录
                        if (chat != null) {
                            Chat.ChatContentItem assistantContentItem = new Chat.ChatContentItem()
                                    .setChatId(chat.getId())
                                    .setRole(ChatRoleEnum.机器人.getProtocolName())
                                    .setContent(sbContent.toString())
                                    .setTimestamp(System.currentTimeMillis());
                            chat.addContentItem(assistantContentItem);
                            chatDao.saveOrUpdate(chat);
                        }
                        return;
                    }
                    // 判断是否繁忙
                    if (content != null && content.contains("code:429") && content.contains("Too Many Requests")) {
                        StreamBusyItemRes item = new StreamBusyItemRes();
                        // 这里不发送[done]，是因为元器那边会发送[done]过来
                        sendStreamMessage(emitter, item, false);
                        return;
                    }

                    StreamChatItemRes resItem = new StreamChatItemRes();
                    resItem.setChatId(chatId)
                            .setRole(ChatRoleEnum.机器人.getProtocolName())
                            .setContent(content)
                            .setTimestamp(System.currentTimeMillis());
                    sendStreamMessage(emitter, resItem, false);
                    // 记录临时对话
                    sbContent.append(content);
                }

                @Override
                public void error(Throwable e) {
                    log.error("调用getQueryChat报错", e);

                    StreamChatItemRes chatItem = new StreamChatItemRes();
                    chatItem.setRole(ChatRoleEnum.机器人.getProtocolName())
                            .setContent("网络错误，请再试一次。" + e.getMessage())
                            .setTimestamp(System.currentTimeMillis());
                    sendStreamMessage(emitter, chatItem, true);
                }
            });

        }).start();

        return emitter;
    }

    private void sendStreamMessage(SseEmitter emitter, Object resItem, boolean done) {
        try {
            if (resItem != null) {
                emitter.send(SseEmitter.event().name("message").data(resItem));
            }
            if (done) {
                emitter.send(SseEmitter.event().name("message").data("[DONE]"));
                emitter.complete();
            }
        } catch (IOException e) {
            emitter.complete(); // 错误处理
        }

    }



}